{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Linux多线程服务端编程:使用muduo C++网络库 : 第11章 反思C++面向对象与虚函数 - 11.7 值语义与数据抽象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本文对“值语义”“对象语义”和“数据抽象”做系统整理，并配有可直接编译运行的 C++ 示例，帮助理解这些概念如何在实践中落地。所有示例假设使用 `g++ -std=c++17` 编译。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 什么是值语义？\n",
    "\n",
    "**值语义（value semantics）** 指对象在拷贝后与原对象相互独立，类似于 `int` 的复制。\n",
    " 典型代表：`bool/int/double/char` 等内置类型，`std::complex`、`std::pair`、`std::vector`、`std::map`、`std::string` 等 STL 类型。\n",
    "\n",
    "> 值语义并不等于不可变（immutable）。一个值语义对象可以是可变的（如 `std::vector`），只是在被复制后彼此互不影响。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 值语义对象的拷贝互不影响"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原始数组：Carol Bob \n",
      "副本数组：Alice Bob \n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <string>\n",
    "#include <vector>\n",
    "\n",
    "{\n",
    "    std::vector<std::string> names{\"Alice\", \"Bob\"};\n",
    "    auto copy = names;  // 复制一份\n",
    "\n",
    "    names[0] = \"Carol\"; // 修改原对象\n",
    "\n",
    "    std::cout << \"原始数组：\";\n",
    "    for (const auto& name : names) {\n",
    "        std::cout << name << ' ';\n",
    "    }\n",
    "    std::cout << \"\\n副本数组：\";\n",
    "    for (const auto& name : copy) {\n",
    "        std::cout << name << ' ';\n",
    "    }\n",
    "    std::cout << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 什么是对象语义（引用语义）？\n",
    "\n",
    "**对象语义（object semantics）** 强调对象是某一资源的唯一代表，因此禁止拷贝。复制这样的对象既不安全也无意义。例如：\n",
    "\n",
    "- 线程（`std::thread`）\n",
    "- 文件句柄、网络连接、物理设备等资源封装对象\n",
    "- `boost::noncopyable` 或显式删除拷贝构造、赋值运算的类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 模拟对象语义的资源封装"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[OfficePrinter] 正在打印报表...\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "\n",
    "class Printer {\n",
    "public:\n",
    "    static std::unique_ptr<Printer> create(std::string name) {\n",
    "        return std::unique_ptr<Printer>(new Printer(std::move(name)));\n",
    "    }\n",
    "\n",
    "    void print(const std::string& text) const {\n",
    "        std::cout << \"[\" << name_ << \"] \" << text << '\\n';\n",
    "    }\n",
    "\n",
    "    Printer(const Printer&) = delete;\n",
    "    Printer& operator=(const Printer&) = delete;\n",
    "\n",
    "private:\n",
    "    explicit Printer(std::string name) : name_(std::move(name)) {}\n",
    "    std::string name_;\n",
    "};\n",
    "\n",
    "{\n",
    "    auto printer = Printer::create(\"OfficePrinter\");\n",
    "    printer->print(\"正在打印报表...\");\n",
    "    // auto copy = *printer; // 编译失败：尝试拷贝对象语义类型; error: call to deleted constructor of 'Printer'\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 值语义与生命周期管理\n",
    "\n",
    "值语义对象通常直接放在栈上或作为成员对象。生命周期与作用域一致，不需额外管理。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 值语义对象的自动销毁"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42 43 \n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <array>\n",
    "\n",
    "class SensorBuffer {\n",
    "public:\n",
    "    void push(int v) {\n",
    "        if (size_ < readings_.size()) {\n",
    "            readings_[size_++] = v;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    void dump() const {\n",
    "        for (std::size_t i = 0; i < size_; ++i) {\n",
    "            std::cout << readings_[i] << ' ';\n",
    "        }\n",
    "        std::cout << '\\n';\n",
    "    }\n",
    "\n",
    "private:\n",
    "    std::array<int, 8> readings_{};\n",
    "    std::size_t size_{0};\n",
    "};\n",
    "\n",
    "{\n",
    "    SensorBuffer buf; // 栈对象，离开作用域自动销毁\n",
    "    buf.push(42);\n",
    "    buf.push(43);\n",
    "    buf.dump();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 对象语义的生命周期问题与智能指针补救\n",
    "\n",
    "对象语义对象常需通过指针/引用共享，伴随悬空指针、重复释放等风险。\n",
    " 现代 C++ 使用智能指针管理资源，从而 **以值方式持有“指针”**，但共享的是真实对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `std::shared_ptr` + `std::weak_ptr` 维护 Parent/Child 关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [],
   "source": [
    "! g++ -std=c++2a -O2 -c shared_ptr.cpp -o shared_ptr_weak_ptr && ./shared_ptr_weak_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 父母引用彼此使用 `weak_ptr`，避免循环引用；孩子引用父母同样用 `weak_ptr`，确保父母离开作用域后不会悬空。\n",
    " \n",
    "#include <iostream>\n",
    "#include <memory>\n",
    "#include <string>\n",
    "#include <vector>\n",
    "\n",
    "struct Parent;\n",
    "struct Child;\n",
    "\n",
    "using ParentPtr = std::shared_ptr<Parent>;\n",
    "using ChildPtr  = std::shared_ptr<Child>;\n",
    "\n",
    "struct Parent {\n",
    "    explicit Parent(std::string name) : name(std::move(name)) {}\n",
    "\n",
    "    void setSpouse(const ParentPtr& spouse) {\n",
    "        spouse_ = spouse;\n",
    "    }\n",
    "\n",
    "    void addChild(const ChildPtr& child) {\n",
    "        children_.push_back(child);\n",
    "    }\n",
    "\n",
    "    void listChildren() const;  // 先声明，函数体稍后定义\n",
    "\n",
    "    std::string name;\n",
    "\n",
    "private:\n",
    "    std::weak_ptr<Parent> spouse_;\n",
    "    std::vector<ChildPtr> children_;\n",
    "};\n",
    "\n",
    "struct Child {\n",
    "    Child(std::string name, const ParentPtr& mom, const ParentPtr& dad)\n",
    "        : name(std::move(name)), mom_(mom), dad_(dad) {}\n",
    "\n",
    "    void showFamily() const {\n",
    "        auto mom = mom_.lock();\n",
    "        auto dad = dad_.lock();\n",
    "        std::cout << name << \" 的父母：\";\n",
    "        std::cout << (mom ? mom->name : \"未知\") << \", \";\n",
    "        std::cout << (dad ? dad->name : \"未知\") << '\\n';\n",
    "    }\n",
    "\n",
    "    std::string name;\n",
    "\n",
    "private:\n",
    "    std::weak_ptr<Parent> mom_;\n",
    "    std::weak_ptr<Parent> dad_;\n",
    "};\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice 的孩子：Carol Dave \n",
      "Bob 的孩子：Carol Dave \n",
      "Carol 的父母：Alice, Bob\n",
      "Dave 的父母：Alice, Bob\n"
     ]
    }
   ],
   "source": [
    "// 现在 Child 已经是完整类型，可以访问 child->name\n",
    "void Parent::listChildren() const {\n",
    "    std::cout << name << \" 的孩子：\";\n",
    "    for (const auto& child : children_) {\n",
    "        if (child) {\n",
    "            std::cout << child->name << ' ';\n",
    "        }\n",
    "    }\n",
    "    std::cout << '\\n';\n",
    "}\n",
    "\n",
    "{\n",
    "    auto mom = std::make_shared<Parent>(\"Alice\");\n",
    "    auto dad = std::make_shared<Parent>(\"Bob\");\n",
    "\n",
    "    mom->setSpouse(dad);\n",
    "    dad->setSpouse(mom);\n",
    "\n",
    "    auto child1 = std::make_shared<Child>(\"Carol\", mom, dad);\n",
    "    auto child2 = std::make_shared<Child>(\"Dave\", mom, dad);\n",
    "\n",
    "    mom->addChild(child1);\n",
    "    mom->addChild(child2);\n",
    "    dad->addChild(child1);\n",
    "    dad->addChild(child2);\n",
    "\n",
    "    mom->listChildren();\n",
    "    dad->listChildren();\n",
    "    child1->showFamily();\n",
    "    child2->showFamily();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 值语义与标准库容器\n",
    "\n",
    "STL 容器要求元素可拷贝（至少可移动），即要满足值语义。编译器默认提供的成员逐一复制即可满足要求。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 自定义值类型放入 STL 容器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <set>\n",
    "\n",
    "struct Point {\n",
    "    int x;\n",
    "    int y;\n",
    "\n",
    "    auto operator<=>(const Point&) const = default; // C++20 三路比较\n",
    "};\n",
    "\n",
    "int main() {\n",
    "    std::set<Point> points{{0, 0}, {1, 2}, {3, 4}};\n",
    "\n",
    "    Point p{1, 2};\n",
    "    std::cout << \"集合中是否包含 (1,2)：\"\n",
    "              << (points.contains(p) ? \"是\" : \"否\") << '\\n';\n",
    "\n",
    "    auto copy = points; // 直接复制整个集合\n",
    "    std::cout << \"副本大小：\" << copy.size() << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 数据抽象（ADT）是什么？\n",
    "\n",
    "**数据抽象（data abstraction）** 关注“数据结构 + 明确的操作 + 性能约束”，并隐藏具体实现。经典 ADT 如栈、队列、链表、关联数组等都应具备值语义（可拷贝）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 温度 ADT（值语义 + 操作 + 运算符重载）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "平均温度：21.75 °C\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "\n",
    "class Temperature {\n",
    "public:\n",
    "    static Temperature fromCelsius(double c) {\n",
    "        return Temperature(c);\n",
    "    }\n",
    "\n",
    "    static Temperature fromFahrenheit(double f) {\n",
    "        return Temperature((f - 32.0) * 5.0 / 9.0);\n",
    "    }\n",
    "\n",
    "    double asCelsius() const { return celsius_; }\n",
    "    double asFahrenheit() const { return celsius_ * 9.0 / 5.0 + 32.0; }\n",
    "\n",
    "    Temperature operator+(Temperature other) const {\n",
    "        return Temperature(celsius_ + other.celsius_);\n",
    "    }\n",
    "\n",
    "    bool operator<(Temperature other) const {\n",
    "        return celsius_ < other.celsius_;\n",
    "    }\n",
    "\n",
    "    bool operator==(Temperature other) const {\n",
    "        return celsius_ == other.celsius_;\n",
    "    }\n",
    "\n",
    "private:\n",
    "    explicit Temperature(double c) : celsius_(c) {}\n",
    "    double celsius_;\n",
    "};\n",
    "\n",
    "{\n",
    "    auto morning = Temperature::fromCelsius(18.5);\n",
    "    auto noon    = Temperature::fromFahrenheit(77.0);\n",
    "\n",
    "    auto average = Temperature::fromCelsius(\n",
    "        (morning.asCelsius() + noon.asCelsius()) / 2.0\n",
    "    );\n",
    "\n",
    "    std::cout << \"平均温度：\" << average.asCelsius() << \" °C\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "该 ADT：\n",
    "\n",
    "- 拥有值语义（可拷贝）\n",
    "- 提供构造与转换函数\n",
    "- 定义比较与算术操作\n",
    "- 隐藏内部表示（摄氏度存储）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7. 数据抽象 vs. 面向对象 vs. 基于对象\n",
    "\n",
    "| 特性       | 数据抽象（ADT）         | 基于对象（Object-based） | 面向对象（OO）             |\n",
    "| ---------- | ----------------------- | ------------------------ | -------------------------- |\n",
    "| 语义       | 值语义                  | 对象语义                 | 对象语义                   |\n",
    "| 是否可拷贝 | 是                      | 通常否                   | 通常否                     |\n",
    "| 关注点     | 数据及操作              | 实体封装                 | 实体 + 抽象接口 + 消息传递 |\n",
    "| 继承/多态  | 不强调                  | 无                       | 强调                       |\n",
    "| 典型例子   | STL 容器、`std::string` | `std::thread`、文件封装  | GUI 控件层次、业务对象体系 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. 支撑数据抽象的语言特性\n",
    "\n",
    "实现 ADT 需要语言提供：\n",
    "\n",
    "1. **数据聚合**（struct/class 内含多个成员）\n",
    "2. **成员函数与访问控制**（操作绑定数据、隐藏细节）\n",
    "3. **函数重载**（全局操作与内置类型形式一致）\n",
    "4. **拷贝控制**（自定义拷贝/赋值/析构，必要时深拷贝）\n",
    "5. **运算符重载**（让 ADT 使用体验接近内置类型）\n",
    "6. **泛型/模板**（复用同一抽象于不同类型）\n",
    "7. **零额外开销目标**（抽象不牺牲性能，保持内存布局紧凑）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 9. 抽象与性能并不矛盾\n",
    "\n",
    "C++ 的设计目标：让用户自定义类型拥有与内置类型相同的地位与效率。\n",
    " 例如 `std::complex<double>`、`std::vector<complex<double>>` 的内存布局紧凑、局部性好；函数传参与返回值虽涉及拷贝构造，但编译器通过 RVO/NRVO 等优化保持零开销原则。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 10. 实践建议\n",
    "\n",
    "- 仅当对象代表“唯一资源”时才禁止拷贝（对象语义）。\n",
    "- 面对资源管理问题优先考虑 RAII（`std::unique_ptr`/`std::shared_ptr`）。\n",
    "- 默认让自定义类型具有值语义，必要时显式删除拷贝。\n",
    "- ADT 关注“操作”与“复杂度”，OO 关注“角色”与“协作”，需根据业务建模场景选择。\n",
    "- 充分利用 C++ 的语言特性（模板、运算符重载）提升抽象层次，同时保持性能。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
